use actix::{Actor, Context, Handler, Message};
use actix::dev::{MessageResponse, OneshotSender};

enum MyMessage {
    Ping,
    Pong,
}

impl Message for MyMessage {
    type Result = Response;
}

enum Response {
    GotPing,
    GotPong,
}

impl<A, M> MessageResponse<A, M> for Response
where
    A: Actor,
    M: Message<Result = Response>,
{
    fn handle(self, _ctx: &mut A::Context, tx: Option<OneshotSender<M::Result>>) {
        if let Some(tx) = tx {
            tx.send(self);
        }
    }
}

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        println!("Actor is alive");
    }

    fn stopped(&mut self, ctx: &mut Self::Context) {
        println!("Actor is stopped")
    }
}

impl Handler<MyMessage> for MyActor {
    type Result = Response;

    fn handle(&mut self, msg: MyMessage, _ctx: &mut Self::Context) -> Self::Result {
        match msg {
            MyMessage::Ping => Response::GotPing,
            MyMessage::Pong => Response::GotPong,
        }
    }
}

#[actix_rt::main]
async fn main() {
    let addr = MyActor.start();

    let ping_future = addr.send(MyMessage::Ping).await;
    let pong_future = addr.send(MyMessage::Pong).await;

   match pong_future {
       Ok(res) => match res {
           Response::GotPing => println!("Ping received"),
           Response::GotPong => println!("Pong received"),
       }
       Err(e) => println!("Actor is probably dead: {}",e),
   }

    match ping_future {
        Ok(res) => match res {
            Response::GotPing => println!("Ping received"),
            Response::GotPong => println!("Pong received"),
        }
        Err(e) => println!("Actor is probably dead: {}", e),
    }

}
